package realDeal;

import sun.security.util.BitArray;

public class Step {
	/**
	 * A bitmap which indicates which counter has overflowed beyond this step
	 */
	private BitArray overflowedMap;

	/**
	 * An array of counters in this current step
	 */
	private BitArray[] counters;

	public Step(int stepIndex, int stepLength, int counterLength, int numOfSteps) {
		if (stepIndex == numOfSteps) { // last step
			overflowedMap = null;
		} else {
			overflowedMap = new BitArray(stepLength);
		}
		this.counters = new BitArray[stepLength];
		initializeCounters(counterLength);
	}

	/**
	 * Create all counters in current step with initialized value of zero
	 * 
	 * @param counterLength
	 *            - size of each counter in this step
	 */
	private void initializeCounters(int counterLength) {
		for (int i = 0; i < counters.length; i++) {
			counters[i] = new BitArray(counterLength);
		}
	}

	/**
	 * Returns the overflowed counters bitmap as a boolean array
	 * 
	 * @return - the overflowed bitmap
	 */
	public boolean[] getOverflowedMap() {
		return overflowedMap.toBooleanArray();
	}

	/**
	 * Returns the counter at a given index as a boolean array
	 * 
	 * @param index
	 *            - the index of the counter to be returned
	 * @return - the requested counter
	 */
	public boolean[] getCounterAt(int index) {
		return counters[index].toBooleanArray();
	}

	/**
	 * Returns whether the counter at a given index has overflowed beyond this
	 * step
	 * 
	 * @param index - index of requested counter
	 * @return - true if counter has overflowed and false otherwise
	 */
	public boolean isOverflowedMapSet(int index) {
		return overflowedMap.get(index);
	}

	/**
	 * Sets the counter at a given index has overflowed to next step
	 * @param index - index of requested counter
	 * @param value - true if counter as overflowed or false otherwise
	 */
	public void setOverflowedMap(int index, boolean value) {
		overflowedMap.set(index, value);
	}

	/**
	 * Returns the amount of counters in current step
	 * @return
	 */
	public int getAmountOfCounters() {
		return counters.length;
	}

	/**
	 * Increment a subcounter in the step at a given index. The change will be
	 * reflected in the step.
	 * 
	 * @param subcounterIndex
	 *            - the subcounter's index
	 * @return - true in case increase resulted a carry or false otherwise
	 */
	public boolean incrementSubcounter(int subcounterIndex) {
		return Statics.incrementBitArray(counters[subcounterIndex]);
	}

	/**
	 * Shift all counters with an index greater than a given index by one
	 * towards the end, and create a zero-valued counter at the given index
	 * Note! - the assumption is that there is enough room for correct shift!
	 */
	public void shift(int counterIndex) {
		int index = counters.length - 1;
		while (index > counterIndex) { // did not reach shift point
			counters[index] = counters[index - 1]; // push counter forward
			index--;
		}
		// create a zero-valued counter instead with same old size
		counters[index] = new BitArray(counters[index].length());
	}
}